"""
数据库窗体 视图 简化版，没有外键
"""
import os
import sys

from PyQt5.QtCore import QDateTime, QDate, Qt, QFile
from PyQt5.QtGui import QIcon, QCursor, QPixmap
from PyQt5.QtSql import QSqlQuery, QSqlTableModel, QSqlDatabase
from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QLineEdit, QDateTimeEdit, QPushButton, QGridLayout, \
    QHBoxLayout, QVBoxLayout, QDataWidgetMapper, QMessageBox

import qrc_resources

MAC = "qt_mac_set_native_menubar" in dir()

ID, CALLER, STARTTIME, ENDTIME, TOPIC = range(5)
DATETIME_FORMAT = "yyyy-MM-dd hh:mm"


def createFakeData():
    import random

    print("Dropping table...")
    query = QSqlQuery()
    query.exec_("DROP TABLE calls")
    QApplication.processEvents()

    print("Creating table...")
    query.exec_("""CREATE TABLE calls (
                id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                caller VARCHAR(40) NOT NULL,
                starttime DATETIME NOT NULL,
                endtime DATETIME NOT NULL,
                topic VARCHAR(80) NOT NULL)""")
    topics = ("Complaint", "Information request", "Off topic",
              "Information supplied", "Complaint", "Complaint")
    now = QDateTime.currentDateTime()
    print("Populating table...")
    query.prepare("INSERT INTO calls (caller, starttime, endtime, "
                  "topic) VALUES (?, ?, ?, ?)")
    for name in ('Joshan Cockerall', 'Ammanie Ingham',
                 'Diarmuid Bettington', 'Juliana Bannister',
                 'Oakley-Jay Buxton', 'Reilley Collinge',
                 'Ellis-James Mcgehee', 'Jazmin Lawton',
                 'Lily-Grace Smythe', 'Coskun Lant', 'Lauran Lanham',
                 'Millar Poindexter', 'Naqeeb Neild', 'Maxlee Stoddart',
                 'Rebia Luscombe', 'Briana Christine', 'Charli Pease',
                 'Deena Mais', 'Havia Huffman', 'Ethan Davie',
                 'Thomas-Jack Silver', 'Harpret Bray', 'Leigh-Ann Goodliff',
                 'Seoras Bayes', 'Jenna Underhill', 'Veena Helps',
                 'Mahad Mcintosh', 'Allie Hazlehurst', 'Aoife Warrington',
                 'Cameron Burton', 'Yildirim Ahlberg', 'Alissa Clayton',
                 'Josephine Weber', 'Fiore Govan', 'Howard Ragsdale',
                 'Tiernan Larkins', 'Seren Sweeny', 'Arisha Keys',
                 'Kiki Wearing', 'Kyran Ponsonby', 'Diannon Pepper',
                 'Mari Foston', 'Sunil Manson', 'Donald Wykes',
                 'Rosie Higham', 'Karmin Raines', 'Tayyibah Leathem',
                 'Kara-jay Knoll', 'Shail Dalgleish', 'Jaimie Sells'):
        start = now.addDays(-random.randint(1, 30))
        start = now.addSecs(-random.randint(60 * 5, 60 * 60 * 2))
        end = start.addSecs(random.randint(20, 60 * 13))
        topic = random.choice(topics)
        query.addBindValue(name)
        query.addBindValue(start)
        query.addBindValue(end)
        query.addBindValue(topic)
        query.exec_()
    QApplication.processEvents()

    print("Calls:")
    query.exec_("SELECT id, caller, starttime, endtime, topic FROM calls "
                "ORDER by starttime")
    print("query")
    while query.next():
        id = int(query.value(0))
        caller = query.value(1)
        starttime = query.value(2)
        endtime = query.value(3)
        topic = query.value(4)
        print("soon print")
        print("{0:02d}: {1} {2} - {3} {4}".format(id, caller,
                                                  starttime, endtime, topic))
    QApplication.processEvents()


class PhoneLogDlg(QDialog):
    FIRST, PREV, NEXT, LAST = range(4)

    def __init__(self, parent=None):
        super(PhoneLogDlg, self).__init__(parent)

        # 表单
        callerLabel = QLabel("&Caller:")
        self.callerEdit = QLineEdit()
        callerLabel.setBuddy(self.callerEdit)
        today = QDate.currentDate()
        startLabel = QLabel("&Start:")
        self.startDateTime = QDateTimeEdit()
        startLabel.setBuddy(self.startDateTime)
        self.startDateTime.setDateRange(today, today)
        self.startDateTime.setDisplayFormat(DATETIME_FORMAT)
        endLabel = QLabel("&End:")
        self.endDateTime = QDateTimeEdit()
        endLabel.setBuddy(self.endDateTime)
        self.endDateTime.setDateRange(today, today)
        self.endDateTime.setDisplayFormat(DATETIME_FORMAT)
        topicLabel = QLabel("&Topic:")
        topicEdit = QLineEdit()
        topicLabel.setBuddy(topicEdit)
        firstButton = QPushButton()
        firstButton.setIcon(QIcon(":/first.png"))
        prevButton = QPushButton()
        prevButton.setIcon(QIcon(":/prev.png"))
        nextButton = QPushButton()
        nextButton.setIcon(QIcon(":/next.png"))
        lastButton = QPushButton()
        lastButton.setIcon(QIcon(":/last.png"))
        addButton = QPushButton("&Add")
        addButton.setIcon(QIcon(":/add.png"))
        deleteButton = QPushButton("&Delete")
        deleteButton.setIcon(QIcon(":/delete.png"))
        quitButton = QPushButton("&Quit")
        quitButton.setIcon(QIcon(":/quit.png"))
        if not MAC:
            addButton.setFocusPolicy(Qt.NoFocus)
            deleteButton.setFocusPolicy(Qt.NoFocus)

        # 布局
        fieldLayout = QGridLayout()
        fieldLayout.addWidget(callerLabel, 0, 0)
        fieldLayout.addWidget(self.callerEdit, 0, 1, 1, 3)
        fieldLayout.addWidget(startLabel, 1, 0)
        fieldLayout.addWidget(self.startDateTime, 1, 1)
        fieldLayout.addWidget(endLabel, 1, 2)
        fieldLayout.addWidget(self.endDateTime, 1, 3)
        fieldLayout.addWidget(topicLabel, 2, 0)
        fieldLayout.addWidget(topicEdit, 2, 1, 1, 3)
        navigationLayout = QHBoxLayout()
        navigationLayout.addWidget(firstButton)
        navigationLayout.addWidget(prevButton)
        navigationLayout.addWidget(nextButton)
        navigationLayout.addWidget(lastButton)
        fieldLayout.addLayout(navigationLayout, 3, 0, 1, 2)
        buttonLayout = QVBoxLayout()
        buttonLayout.addWidget(addButton)
        buttonLayout.addWidget(deleteButton)
        buttonLayout.addStretch()
        buttonLayout.addWidget(quitButton)
        layout = QHBoxLayout()
        layout.addLayout(fieldLayout)
        layout.addLayout(buttonLayout)
        self.setLayout(layout)

        # 模型
        # 没有外键所以使用QSqlTableModel，默认连接在main()函数中
        self.model = QSqlTableModel(self)
        self.model.setTable("calls")
        self.model.setSort(STARTTIME, Qt.AscendingOrder)
        self.model.select()  # 填充数据

        # 在表单和模型之间建立映射
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setModel(self.model)
        self.mapper.addMapping(self.callerEdit, CALLER)  # addMapping(widget,section),section是模型的字段序号
        self.mapper.addMapping(self.startDateTime, STARTTIME)
        self.mapper.addMapping(self.endDateTime, ENDTIME)
        self.mapper.addMapping(topicEdit, TOPIC)
        self.mapper.toFirst()  # Populates the widgets with data from the first row of the model

        firstButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.FIRST))
        # lambda函数是纯粹为了传递参数而来的。一般情况下，参数是在signal函数中指定的，然后在slot函数定义中有相应的参数来
        # 接收即可，但是这里传递了额外的参数，不是信号中指定的，所以有这样一个机制。
        prevButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.PREV))
        nextButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.NEXT))
        lastButton.clicked.connect(lambda: self.saveRecord(PhoneLogDlg.LAST))
        addButton.clicked.connect(self.addRecord)
        deleteButton.clicked.connect(self.deleteLater)
        quitButton.clicked.connect(self.accept)

        self.setWindowTitle("Phone Log")

    def reject(self):
        self.accept()

    def accept(self):
        self.mapper.submit()
        QDialog.accept(self)

    def addRecord(self):
        row = self.model.rowCount()
        self.mapper.submit()
        self.model.insertRow(row)
        # Inserts a single row before the given row in the child items of the parent specified.
        self.mapper.setCurrentIndex(row)
        now = QDateTime.currentDateTime()
        self.startDateTime.setDateTime(now)
        self.endDateTime.setDateTime(now)
        self.callerEdit.setFocus()  # 为用户输入作准备

    def deleteRecord(self):
        caller = self.callerEdit.text()
        starttime = self.startDateTime.dateTime().toString()
        if (QMessageBox.question(self,
                                 "Delete",
                                 "Delete call made by<br>{} on {}?".format(
                                     caller, starttime),
                                 QMessageBox.Yes | QMessageBox.No) ==
                QMessageBox.No):
            return
        row = self.mapper.currentIndex()
        self.model.removeRow(row)
        self.model.submitAll()
        if row + 1 >= self.model.rowCount():
            row = self.model.rowCount() - 1
        self.mapper.setCurrentIndex(row)

    def saveRecord(self, where):

        row = self.mapper.currentIndex()  # 保存当前记录，然后响应导航，否则当前记录会丢失。
        self.mapper.submit()  # Submits all changes from the mapped widgets to the model.
        if where == PhoneLogDlg.FIRST:
            row = 0
        elif where == PhoneLogDlg.PREV:
            row = 0 if row <= 1 else row - 1
        elif where == PhoneLogDlg.NEXT:
            row += 1
            if row >= self.model.rowCount():
                row = self.model.rowCount() - 1
        elif where == PhoneLogDlg.LAST:
            row = self.model.rowCount() - 1
        self.mapper.setCurrentIndex(row)


def main():
    app = QApplication(sys.argv)

    filename = os.path.join(os.path.dirname(__file__), "phonelog.db")
    create = not QFile.exists(filename)

    db = QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName(filename)
    if not db.open():
        QMessageBox.warning(None, "Phone Log",
                            "Database Error: {}".format(db.lastError().text()))
        sys.exit(1)

    splash = None
    if create:
        app.setOverrideCursor(QCursor(Qt.WaitCursor))
        splash = QLabel()
        pixmap = QPixmap(":/phonelogsplash.png")
        splash.setPixmap(pixmap)
        splash.setMask(pixmap.createHeuristicMask())
        splash.setWindowFlags(Qt.SplashScreen)
        rect = app.desktop().availableGeometry()
        splash.move((rect.width() - pixmap.width()) / 2,
                    (rect.height() - pixmap.height()) / 2)
        splash.show()
        app.processEvents()
        createFakeData()

    form = PhoneLogDlg()
    form.show()
    if create:
        splash.close()
        app.processEvents()
        app.restoreOverrideCursor()
    sys.exit(app.exec_())


if __name__ == '__main__':
    # createFakeData()
    main()
